# -*- coding: utf-8 -*-
"""word2pdf_mixin
基于用户原版 `word to pdf.py` 逻辑改造，去除独立 Tk GUI，封装为 mixin。
在主窗口中已创建 "Word转PDF" 标签页并绑定以下方法：
    • select_word_files           – 选择 Word 文件
    • select_word_output_folder   – 选择输出目录
    • update_word_file_list       – 更新列表显示
    • start_word2pdf_conversion   – 启动转换线程

依赖字段（已在 main.PDFConverter.__init__ 初始化）：
    self.word_paths: list[str]
    self.word_output_path: str
    self.is_converting: bool

依赖 UI 组件（create_word2pdf_widgets 创建）：
    self.word_file_listbox
    self.word_progress_bar
    self.word_status_label
    self.word_convert_btn
"""

from __future__ import annotations

import os
import sys
import threading
import traceback
from datetime import datetime
from tkinter import filedialog, messagebox

import pythoncom
from comtypes.client import CreateObject
import subprocess

__all__ = ["Word2PdfMixin"]


class Word2PdfMixin:
    """Word ➜ PDF 批量转换功能 mixin"""

    # ------------------------------------------------------------------
    # 选择文件 / 输出目录 & UI 更新
    # ------------------------------------------------------------------
    def select_word_files(self):  # type: ignore[override]
        """选择 Word 文件 (可多选)"""
        if self.is_converting:
            messagebox.showwarning("警告", "正在进行其他转换，请稍后")
            return

        files = filedialog.askopenfilenames(
            title="选择需要转换的 Word 文件",
            filetypes=[("Word 文件", "*.docx *.doc"), ("所有文件", "*.*")],
        )
        if files:
            # 直接存储为列表
            self.word_paths = list(files)
            self.update_word_file_list()

    def select_word_output_folder(self):  # type: ignore[override]
        """选择输出目录"""
        if self.is_converting:
            messagebox.showwarning("警告", "正在进行其他转换，请稍后")
            return

        folder = filedialog.askdirectory(title="选择输出目录")
        if folder:
            self.word_output_path = folder
            self.update_word_file_list()

    def update_word_file_list(self):  # type: ignore[override]
        """在列表框中显示已选文件和输出目录"""
        if not hasattr(self, "word_file_listbox"):
            return

        self.word_file_listbox.configure(state="normal")
        self.word_file_listbox.delete("1.0", "end")
        self.word_file_listbox.insert("1.0", "选择的 Word 文件：\n\n")
        for path in self.word_paths:
            self.word_file_listbox.insert("end", f"{os.path.basename(path)}\n")
        if self.word_output_path:
            self.word_file_listbox.insert("end", f"\n输出目录：{self.word_output_path}\n")
        self.word_file_listbox.configure(state="disabled")

    # ------------------------------------------------------------------
    # 转换线程入口
    # ------------------------------------------------------------------
    def start_word2pdf_conversion(self):  # type: ignore[override]
        """验证输入并启动后台线程"""
        if self.is_converting:
            messagebox.showwarning("提示", "正在进行其他转换，请稍后")
            return
        if not self.word_paths:
            messagebox.showerror("错误", "请先选择 Word 文件")
            return
        if not self.word_output_path:
            messagebox.showerror("错误", "请先选择输出目录")
            return

        # UI 状态
        self.is_converting = True
        self.word_convert_btn.configure(state="disabled")
        self.word_status_label.configure(text="开始转换...")
        self.word_progress_bar.set(0)

        threading.Thread(target=self.convert_word_thread, daemon=True).start()

    # ------------------------------------------------------------------
    # 后台线程核心逻辑（移植自原版）
    # ------------------------------------------------------------------
    def convert_single_file(self, file_path: str, word_app):
        """转换单个 Word 文件到 PDF。返回 (success, info)。"""
        try:
            if not os.path.exists(file_path):
                return False, f"文件不存在: {file_path}"

            # 打开 Word 文档
            doc = word_app.Documents.Open(file_path)

            # 输出路径
            output_name = os.path.splitext(os.path.basename(file_path))[0] + ".pdf"
            output_path = os.path.join(self.word_output_path, output_name)
            output_path = os.path.abspath(output_path).replace("/", "\\")

            # 保存为 PDF (17 = wdFormatPDF)
            doc.SaveAs(output_path, FileFormat=17)
            doc.Close(SaveChanges=False)
            return True, output_path
        except Exception as exc:  # noqa: BLE001
            return False, f"转换过程出错: {exc}"

    def convert_word_thread(self):  # type: ignore[override]
        """批量转换线程包装器"""
        success_count = 0
        error_files: list[tuple[str, str]] = []
        total_files = len(self.word_paths)

        pythoncom.CoInitialize()
        word_app = None
        try:
            # 创建 Word 实例
            word_app = CreateObject("Word.Application")  # type: ignore
            word_app.Visible = False
            word_app.DisplayAlerts = False

            # 确保输出目录存在
            os.makedirs(self.word_output_path, exist_ok=True)

            for index, file_path in enumerate(self.word_paths, 1):
                if not self.is_converting:
                    break  # 用户取消

                # 更新进度
                progress = index / total_files
                status_text = f"正在转换 {index}/{total_files}: {os.path.basename(file_path)}"
                self.after(0, self._update_word_progress_ui, progress, status_text)

                success, info = self.convert_single_file(file_path, word_app)
                if success:
                    success_count += 1
                else:
                    error_files.append((file_path, info))

        except Exception as exc:  # noqa: BLE001
            err_detail = traceback.format_exc()
            self.after(0, messagebox.showerror, "错误", f"转换过程中发生异常:\n{exc}\n{err_detail}")
        finally:
            # 释放资源
            if word_app:
                try:
                    word_app.Quit()
                except Exception:
                    pass
            pythoncom.CoUninitialize()
            self.cleanup_word_processes()

            # 报告 & 重置 UI
            self.after(0, self.create_conversion_report, success_count, error_files, total_files)
            self.after(0, self._reset_word_ui_state)

    # ------------------------------------------------------------------
    # 共享辅助方法
    # ------------------------------------------------------------------
    def _update_word_progress_ui(self, progress: float, status_text: str):
        if self.word_progress_bar:
            self.word_progress_bar.set(progress)
        if self.word_status_label:
            self.word_status_label.configure(text=status_text)
        self.update_idletasks()

    def _reset_word_ui_state(self):
        """线程结束后恢复按钮状态等"""
        self.is_converting = False
        self.word_convert_btn.configure(state="normal")
        self.word_status_label.configure(text="准备就绪")
        self.word_progress_bar.set(0)

    # ---------------------- 原版辅助函数移植 ----------------------
    def cleanup_word_processes(self):  # noqa: D401 – 命名保持一致
        """清理可能残留的 WINWORD 进程"""
        try:
            if sys.platform == "win32":
                subprocess.run(
                    "taskkill /f /im WINWORD.EXE",
                    shell=True,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                    check=False,
                )
        except Exception:
            pass

    def create_conversion_report(
        self, success_count: int, error_files: list[tuple[str, str]], total_files: int
    ):
        """生成转换完成报告"""
        if success_count:
            messagebox.showinfo("完成", f"转换完成！\n成功: {success_count}\n失败: {len(error_files)}")

        if error_files:
            log_path = os.path.join(self.word_output_path, "转换错误日志.txt")
            try:
                with open(log_path, "w", encoding="utf-8") as f:
                    f.write(f"转换时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
                    for fp, err in error_files:
                        f.write(f"文件: {os.path.basename(fp)}\n")
                        f.write(f"错误: {err}\n\n")
                messagebox.showwarning("警告", f"部分文件转换失败，详细信息已保存到:\n{log_path}")
            except Exception as exc:  # noqa: BLE001
                messagebox.showerror("错误", f"创建错误日志文件失败：{exc}")